home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / term / extras / source / term-source.lha / termBuffer.c < prev    next >
C/C++ Source or Header  |  1995-02-15  |  29KB  |  1,435 lines

  1. /*
  2. **    termBuffer.c
  3. **
  4. **    Auxilary routines for text buffer/capture management.
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Search string window gadgets. */
  13.  
  14. enum    {    GAD_STRING,GAD_OK,GAD_CANCEL };
  15.  
  16.     /* Maximum size of an allocated line string. */
  17.  
  18. #define STRING_SIZE    (1 + 255 + 1)
  19.  
  20.     /* How many strings to include in a single puddle. */
  21.  
  22. #define STRING_COUNT    10
  23.  
  24.     /* The number of lines the buffer will grow. */
  25.  
  26. #define BUFFER_GROW    100
  27.  
  28.     /* Memory pool header. */
  29.  
  30. STATIC APTR        BufferPoolHeader;
  31.  
  32.     /* Word separator characters. */
  33.  
  34. STATIC BYTE WordSeparators[256] =
  35. {
  36.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  37.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  38.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  39.     0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
  40.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  41.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  42.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  43.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  44.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  45.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  46.     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  47.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  48.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  49.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  50.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  51.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0
  52. };
  53.  
  54.     /* AllocString(STRPTR String,WORD Len):
  55.      *
  56.      +    Allocate space for a string, new pooled version.
  57.      */
  58.  
  59. STATIC STRPTR __regargs
  60. AllocString(STRPTR String,LONG Len)
  61. {
  62.     STRPTR Mem;
  63.  
  64.     if(Len > 255)
  65.         Len = 255;
  66.  
  67.     if(Mem = (STRPTR)LibAllocPooled(BufferPoolHeader,1 + Len + 1))
  68.     {
  69.         *Mem++ = Len;
  70.  
  71.         if(Len)
  72.             CopyMem(String,Mem,Len);
  73.  
  74.         Mem[Len] = 0;
  75.  
  76.         return((STRPTR)Mem);
  77.     }
  78.     else
  79.         return(NULL);
  80. }
  81.  
  82.     /* FreeString(STRPTR String):
  83.      *
  84.      *    Free the space occupied by a string, new pooled version.
  85.      */
  86.  
  87. STATIC VOID __regargs
  88. FreeString(STRPTR String)
  89. {
  90.     LibFreePooled(BufferPoolHeader,&String[-1],1 + String[-1] + 1);
  91. }
  92.  
  93.     /* AddLine(STRPTR Line,LONG Size):
  94.      *
  95.      *    Add a line to the display buffer.
  96.      */
  97.  
  98. VOID __regargs
  99. AddLine(register STRPTR Line,register LONG Size)
  100. {
  101. /*
  102.     while(Size > 0 && Line[Size - 1] == ' ')
  103.         Size--;
  104. */
  105.         /* Are we still to update the buffer contents? */
  106.  
  107.     if(!BufferClosed)
  108.     {
  109.             /* Is the buffer array initialized? */
  110.  
  111.         if(BufferLines)
  112.         {
  113.             ULONG Signals = 0;
  114.  
  115.                 /* Pick up the global access semaphore
  116.                  * (two tasks are sharing the data).
  117.                  */
  118.  
  119.             ObtainSemaphore(BufferSemaphore);
  120.  
  121.                 /* Check for limit. */
  122.  
  123.             if(Config -> CaptureConfig -> MaxBufferSize && BufferSpace >= Config -> CaptureConfig -> MaxBufferSize)
  124.             {
  125.                 register LONG i;
  126.  
  127.                 BufferSpace -= BufferLines[0][-1];
  128.  
  129.                 FreeString(BufferLines[0]);
  130.  
  131.                 for(i = 1 ; i < MaxLines ; i++)
  132.                     BufferLines[i - 1] = BufferLines[i];
  133.  
  134.                 Lines--;
  135.  
  136.                     /* Tell the buffer task to
  137.                      * refresh the display.
  138.                      */
  139.  
  140.                 Signals = SIG_MOVEUP;
  141.             }
  142.             else
  143.             {
  144.                     /* We've reached the last line in the buffer. */
  145.  
  146.                 if(Lines == MaxLines)
  147.                 {
  148.                     STRPTR *MoreBuffer;
  149.  
  150.                         /* Allocate space for some more lines. */
  151.  
  152.                     if(MoreBuffer = (STRPTR *)AllocVecPooled((MaxLines + BUFFER_GROW) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  153.                     {
  154.                         register LONG i;
  155.  
  156.                         BufferChanged = TRUE;
  157.  
  158.                             /* Copy the old lines to the new
  159.                              * buffer.
  160.                              */
  161.  
  162.                         for(i = 0 ; i < Lines ; i++)
  163.                             MoreBuffer[i] = BufferLines[i];
  164.  
  165.                             /* Free the old lines. */
  166.  
  167.                         FreeVecPooled(BufferLines);
  168.  
  169.                             /* Set the new buffer. */
  170.  
  171.                         MaxLines += BUFFER_GROW;
  172.  
  173.                         BufferLines = MoreBuffer;
  174.                     }
  175.                     else
  176.                     {
  177.                         BufferChanged = TRUE;
  178.  
  179.                             /* We couldn't get enough memory
  180.                              * to extend the number of lines
  181.                              * in the buffer, so we'll have
  182.                              * to wrap the contents of the
  183.                              * buffer around.
  184.                              */
  185.  
  186.                         if(Lines)
  187.                         {
  188.                             register LONG i;
  189.  
  190.                             BufferSpace -= BufferLines[0][-1];
  191.  
  192.                             FreeString(BufferLines[0]);
  193.  
  194.                             for(i = 1 ; i < MaxLines ; i++)
  195.                                 BufferLines[i - 1] = BufferLines[i];
  196.  
  197.                             Lines--;
  198.  
  199.                                 /* Tell the buffer task to
  200.                                  * refresh the display.
  201.                                  */
  202.  
  203.                             Signals = SIG_MOVEUP;
  204.                         }
  205.                     }
  206.                 }
  207.             }
  208.  
  209.                 /* Allocate a new line and copy the buffer contents
  210.                  * into it.
  211.                  */
  212.  
  213.             if(BufferLines[Lines] = AllocString(Line,Size))
  214.             {
  215.                 BufferChanged = TRUE;
  216.  
  217.                 Lines++;
  218.  
  219.                 BufferSpace += Size;
  220.             }
  221.  
  222.             ReleaseSemaphore(BufferSemaphore);
  223.  
  224.                 /* Tell the buffer task to update the display. */
  225.  
  226.             if(!Signals)
  227.             {
  228.                 Signals = SIG_UPDATE;
  229.  
  230.                 UpdateReview(FALSE);
  231.             }
  232.             else
  233.                 UpdateReview(TRUE);
  234.  
  235.             ObtainSemaphore(&BufferTaskSemaphore);
  236.  
  237.             if(BufferTask && Signals)
  238.             {
  239.                 Forbid();
  240.  
  241.                 ClrSignal(SIG_HANDSHAKE);
  242.  
  243.                 Signal(BufferTask,Signals);
  244.  
  245.                 Wait(SIG_HANDSHAKE);
  246.  
  247.                 Permit();
  248.             }
  249.  
  250.             ReleaseSemaphore(&BufferTaskSemaphore);
  251.         }
  252.     }
  253. }
  254.  
  255.     /* DeleteBuffer():
  256.      *
  257.      *    Delete buffer resources.
  258.      */
  259.  
  260. VOID
  261. DeleteBuffer()
  262. {
  263.     if(BufferLines)
  264.     {
  265.         FreeVecPooled(BufferLines);
  266.  
  267.         BufferLines = NULL;
  268.     }
  269.  
  270.     if(BufferPoolHeader)
  271.     {
  272.         LibDeletePool(BufferPoolHeader);
  273.  
  274.         BufferPoolHeader = NULL;
  275.     }
  276.  
  277.     if(BufferSemaphore)
  278.     {
  279.         FreeVecPooled(BufferSemaphore);
  280.  
  281.         BufferSemaphore = NULL;
  282.     }
  283. }
  284.  
  285.     /* CreateBuffer():
  286.      *
  287.      *    Allocate buffer resources.
  288.      */
  289.  
  290. BYTE
  291. CreateBuffer()
  292. {
  293.     if(BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  294.     {
  295.         if(BufferSemaphore = (struct SignalSemaphore *)AllocVecPooled(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  296.         {
  297.             InitSemaphore(BufferSemaphore);
  298.  
  299.                 /* Create a memory pool header if possible. */
  300.  
  301.             if(BufferPoolHeader = LibCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
  302.                 return(TRUE);
  303.         }
  304.  
  305.         FreeVecPooled(BufferLines);
  306.  
  307.         BufferLines = NULL;
  308.     }
  309.  
  310.     return(FALSE);
  311. }
  312.  
  313.     /* FreeBuffer():
  314.      *
  315.      *    Release the contents of the text buffer.
  316.      */
  317.  
  318. VOID
  319. FreeBuffer()
  320. {
  321.         /* Free the contents of the display buffer. */
  322.  
  323.     if(BufferLines)
  324.     {
  325.         APTR NewPoolHeader;
  326.  
  327.         ObtainSemaphore(BufferSemaphore);
  328.  
  329.             /* If a new pool header is available, free the old
  330.              * pool and replace it with the new pool.
  331.              */
  332.  
  333.         if(NewPoolHeader = LibCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
  334.         {
  335.             LibDeletePool(BufferPoolHeader);
  336.  
  337.             BufferPoolHeader = NewPoolHeader;
  338.         }
  339.         else
  340.         {
  341.             LONG i;
  342.  
  343.             for(i = 0 ; i < Lines ; i++)
  344.             {
  345.                 if(BufferLines[i])
  346.                     FreeString(BufferLines[i]);
  347.             }
  348.         }
  349.  
  350.         FreeVecPooled(BufferLines);
  351.  
  352.         Lines = 0;
  353.  
  354.         MaxLines = BUFFER_GROW;
  355.  
  356.         BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR);
  357.  
  358.         ReleaseSemaphore(BufferSemaphore);
  359.  
  360.         UpdateReview(TRUE);
  361.     }
  362.  
  363.     BufferSpace = 0;
  364.  
  365.     BufferChanged = FALSE;
  366. }
  367.  
  368.     /* DeleteSearchInfo(struct SearchInfo *Info):
  369.      *
  370.      *    Free buffer allocated by CreateSearchInfo().
  371.      */
  372.  
  373. VOID __regargs
  374. DeleteSearchInfo(struct SearchInfo *Info)
  375. {
  376.     if(Info)
  377.         FreeVecPooled(Info);
  378. }
  379.  
  380.     /* CreateSearchInfo(STRPTR Pattern):
  381.      *
  382.      *    Create auxilary data required by SearchTextBuffer().
  383.      */
  384.  
  385. struct SearchInfo * __regargs
  386. CreateSearchInfo(STRPTR Pattern,BOOLEAN Forward,BOOLEAN IgnoreCase,BOOLEAN WholeWords)
  387. {
  388.     struct SearchInfo *Info;
  389.  
  390.         /* Allocate the buffer. */
  391.  
  392.     if(Info = (struct SearchInfo *)AllocVecPooled(sizeof(struct SearchInfo),MEMF_ANY | MEMF_PUBLIC))
  393.     {
  394.         WORD i;
  395.  
  396.             /* Determine pattern width. */
  397.  
  398.         Info -> PatternWidth    = strlen(Pattern);
  399.         Info -> IgnoreCase    = IgnoreCase;
  400.  
  401.         if(Info -> PatternWidth == 1)
  402.         {
  403.             if(WordSeparators[Pattern[0]])
  404.                 WholeWords = FALSE;
  405.         }
  406.  
  407.         Info -> WholeWords = WholeWords;
  408.  
  409.             /* Turn the pattern into upper case characters. */
  410.  
  411.         if(IgnoreCase)
  412.         {
  413.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  414.                 Info -> Pattern[i] = ToUpper(Pattern[i]);
  415.         }
  416.         else
  417.         {
  418.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  419.                 Info -> Pattern[i] = Pattern[i];
  420.         }
  421.  
  422.             /* Fill the entire range with the maximum pattern width. */
  423.  
  424.         for(i = 0 ; i < 256 ; i++)
  425.             Info -> Distance[i] = Info -> PatternWidth;
  426.  
  427.             /* Fill in the matching distances. */
  428.  
  429.         if(Forward)
  430.         {
  431.             for(i = 0 ; i < Info -> PatternWidth - 1 ; i++)
  432.                 Info -> Distance[Info -> Pattern[i]] = Info -> PatternWidth - 1 - i;
  433.         }
  434.         else
  435.         {
  436.             for(i = Info -> PatternWidth - 1 ; i > 0 ; i--)
  437.                 Info -> Distance[Info -> Pattern[i]] = i;
  438.         }
  439.  
  440.             /* Restart from scratch. */
  441.  
  442.         Info -> FoundY    = -1;
  443.         Info -> Forward    = Forward;
  444.     }
  445.  
  446.     return(Info);
  447. }
  448.  
  449.     /* SearchTextBuffer():
  450.      *
  451.      *    String search function, based on the Boyer-Moore search
  452.      *    algorithm.
  453.      */
  454.  
  455. LONG __regargs
  456. SearchTextBuffer(struct SearchInfo *Info)
  457. {
  458.     if(BufferLines)
  459.     {
  460.         UBYTE    *Distance,
  461.             *Pattern;
  462.         WORD    LineWidth,
  463.             PatternWidth;
  464.         STRPTR    Line;
  465.  
  466.         LONG    i;
  467.         WORD    SearchPosition,PatternIndex,LineIndex,LastSearchPosition;
  468.  
  469.             /* Extract the relevant data. */
  470.  
  471.         Distance    = Info -> Distance;
  472.         Pattern        = Info -> Pattern;
  473.         PatternWidth    = Info -> PatternWidth;
  474.  
  475.         if(Info -> WholeWords)
  476.         {
  477.                 /* Which direction are we to search? */
  478.  
  479.             if(Info -> IgnoreCase)
  480.             {
  481.                 if(Info -> Forward)
  482.                 {
  483.                         /* Update the search positions. */
  484.  
  485.                     if(Info -> FoundY == -1)
  486.                     {
  487.                         Info -> FoundX        = 0;
  488.                         Info -> FoundY        = 0;
  489.                         LastSearchPosition    = 0;
  490.                     }
  491.                     else
  492.                     {
  493.                             /* Proceed to the next line. */
  494.  
  495.                         if(!(LastSearchPosition = Info -> Index))
  496.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  497.                     }
  498.  
  499.                         /* Run down the buffer. */
  500.  
  501.                     for(i = Info -> FoundY ; i < Lines ; i++)
  502.                     {
  503.                         Line = BufferLines[i];
  504.  
  505.                             /* Is there anything to search for? */
  506.  
  507.                         if((LineWidth = Line[-1]) >= PatternWidth)
  508.                         {
  509.                                 /* Where are we to start searching? */
  510.  
  511.                             if(LastSearchPosition)
  512.                                 SearchPosition = LastSearchPosition;
  513.                             else
  514.                                 SearchPosition = PatternWidth;
  515.  
  516.                             do
  517.                             {
  518.                                     /* How many line characters
  519.                                      * match the pattern?
  520.                                      */
  521.  
  522.                                 PatternIndex    = PatternWidth - 1;
  523.                                 LineIndex    = SearchPosition - 1;
  524.  
  525.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  526.                                 {
  527.                                     LineIndex--;
  528.                                     PatternIndex--;
  529.                                 }
  530.  
  531.                                     /* Update the line search index
  532.                                      * for subsequent searches.
  533.                                      */
  534.  
  535.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  536.  
  537.                                     /* Found the pattern? */
  538.  
  539.                                 if(PatternIndex < 0)
  540.                                 {
  541.                                     LONG X = LineIndex + 1;
  542.  
  543.                                     if(X)
  544.                                     {
  545.                                         if(!WordSeparators[Line[X - 1]])
  546.                                             continue;
  547.                                         else
  548.                                         {
  549.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  550.                                                 continue;
  551.                                         }
  552.                                     }
  553.                                     else
  554.                                     {
  555.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  556.                                             continue;
  557.                                     }
  558.  
  559.                                         /* Store the position. */
  560.  
  561.                                     Info -> FoundX    = LineIndex + 1;
  562.                                     Info -> FoundY    = i;
  563.  
  564.                                         /* Remember column to start
  565.                                          * next search attempt at.
  566.                                          */
  567.  
  568.                                     if(SearchPosition <= LineWidth)
  569.                                         Info -> Index = SearchPosition;
  570.                                     else
  571.                                         Info -> Index = 0;
  572.  
  573.                                     return(i);
  574.                                 }
  575.                             }
  576.                             while(SearchPosition <= LineWidth);
  577.                         }
  578.  
  579.                             /* Reset search column. */
  580.  
  581.                         LastSearchPosition = 0;
  582.                     }
  583.                 }
  584.                 else
  585.                 {
  586.                         /* Update the search positions. */
  587.  
  588.                     if(Info -> FoundY == -1)
  589.                     {
  590.                         Info -> FoundX        = 0;
  591.                         Info -> FoundY        = Lines - 1;
  592.                         LastSearchPosition    = 0;
  593.                     }
  594.                     else
  595.                     {
  596.                         if((LastSearchPosition = Info -> Index) < 1)
  597.                         {
  598.                             if(Info -> FoundY)
  599.                                 Info -> FoundY--;
  600.                             else
  601.                                 Info -> FoundY = Lines - 1;
  602.                         }
  603.                     }
  604.  
  605.                         /* Run down the buffer. */
  606.  
  607.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  608.                     {
  609.                         Line = BufferLines[i];
  610.  
  611.                             /* Is there anything to search for? */
  612.  
  613.                         if((LineWidth = Line[-1]) >= PatternWidth)
  614.                         {
  615.                                 /* Cast the magic spell of Boyer-Moore... */
  616.  
  617.                             if(LastSearchPosition < 1)
  618.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  619.                             else
  620.                                 SearchPosition = LastSearchPosition;
  621.  
  622.                             do
  623.                             {
  624.                                 PatternIndex = 0;
  625.                                 LineIndex = SearchPosition - 1;
  626.  
  627.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  628.                                 {
  629.                                     LineIndex++;
  630.                                     PatternIndex++;
  631.                                 }
  632.  
  633.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  634.  
  635.                                 if(PatternIndex == PatternWidth)
  636.                                 {
  637.                                     LONG X = LineIndex - PatternWidth;
  638.  
  639.                                     if(X)
  640.                                     {
  641.                                         if(!WordSeparators[Line[X - 1]])
  642.                                             continue;
  643.                                         else
  644.                                         {
  645.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  646.                                                 continue;
  647.                                         }
  648.                                     }
  649.                                     else
  650.                                     {
  651.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  652.                                             continue;
  653.                                     }
  654.  
  655.                                     Info -> FoundX    = LineIndex - PatternWidth;
  656.                                     Info -> FoundY    = i;
  657.                                     Info -> Index    = SearchPosition;
  658.  
  659.                                     return(i);
  660.                                 }
  661.                             }
  662.                             while(SearchPosition > 0);
  663.                         }
  664.  
  665.                         LastSearchPosition = 0;
  666.                     }
  667.                 }
  668.             }
  669.             else
  670.             {
  671.                 if(Info -> Forward)
  672.                 {
  673.                         /* Update the search positions. */
  674.  
  675.                     if(Info -> FoundY == -1)
  676.                     {
  677.                         Info -> FoundX        = 0;
  678.                         Info -> FoundY        = 0;
  679.                         LastSearchPosition    = 0;
  680.                     }
  681.                     else
  682.                     {
  683.                             /* Proceed to the next line. */
  684.  
  685.                         if(!(LastSearchPosition = Info -> Index))
  686.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  687.                     }
  688.  
  689.                         /* Run down the buffer. */
  690.  
  691.                     for(i = Info -> FoundY ; i < Lines ; i++)
  692.                     {
  693.                         Line = BufferLines[i];
  694.  
  695.                             /* Is there anything to search for? */
  696.  
  697.                         if((LineWidth = Line[-1]) >= PatternWidth)
  698.                         {
  699.                                 /* Where are we to start searching? */
  700.  
  701.                             if(LastSearchPosition)
  702.                                 SearchPosition = LastSearchPosition;
  703.                             else
  704.                                 SearchPosition = PatternWidth;
  705.  
  706.                             do
  707.                             {
  708.                                     /* How many line characters
  709.                                      * match the pattern?
  710.                                      */
  711.  
  712.                                 PatternIndex    = PatternWidth - 1;
  713.                                 LineIndex    = SearchPosition - 1;
  714.  
  715.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  716.                                 {
  717.                                     LineIndex--;
  718.                                     PatternIndex--;
  719.                                 }
  720.  
  721.                                     /* Update the line search index
  722.                                      * for subsequent searches.
  723.                                      */
  724.  
  725.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  726.  
  727.                                     /* Found the pattern? */
  728.  
  729.                                 if(PatternIndex < 0)
  730.                                 {
  731.                                     LONG X = LineIndex + 1;
  732.  
  733.                                     if(X)
  734.                                     {
  735.                                         if(!WordSeparators[Line[X - 1]])
  736.                                             continue;
  737.                                         else
  738.                                         {
  739.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  740.                                                 continue;
  741.                                         }
  742.                                     }
  743.                                     else
  744.                                     {
  745.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  746.                                             continue;
  747.                                     }
  748.  
  749.                                         /* Store the position. */
  750.  
  751.                                     Info -> FoundX    = LineIndex + 1;
  752.                                     Info -> FoundY    = i;
  753.  
  754.                                         /* Remember column to start
  755.                                          * next search attempt at.
  756.                                          */
  757.  
  758.                                     if(SearchPosition <= LineWidth)
  759.                                         Info -> Index = SearchPosition;
  760.                                     else
  761.                                         Info -> Index = 0;
  762.  
  763.                                     return(i);
  764.                                 }
  765.                             }
  766.                             while(SearchPosition <= LineWidth);
  767.                         }
  768.  
  769.                             /* Reset search column. */
  770.  
  771.                         LastSearchPosition = 0;
  772.                     }
  773.                 }
  774.                 else
  775.                 {
  776.                         /* Update the search positions. */
  777.  
  778.                     if(Info -> FoundY == -1)
  779.                     {
  780.                         Info -> FoundX        = 0;
  781.                         Info -> FoundY        = Lines - 1;
  782.                         LastSearchPosition    = 0;
  783.                     }
  784.                     else
  785.                     {
  786.                         if((LastSearchPosition = Info -> Index) < 1)
  787.                         {
  788.                             if(Info -> FoundY)
  789.                                 Info -> FoundY--;
  790.                             else
  791.                                 Info -> FoundY = Lines - 1;
  792.                         }
  793.                     }
  794.  
  795.                         /* Run down the buffer. */
  796.  
  797.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  798.                     {
  799.                         Line = BufferLines[i];
  800.  
  801.                             /* Is there anything to search for? */
  802.  
  803.                         if((LineWidth = Line[-1]) >= PatternWidth)
  804.                         {
  805.                                 /* Cast the magic spell of Boyer-Moore... */
  806.  
  807.                             if(LastSearchPosition < 1)
  808.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  809.                             else
  810.                                 SearchPosition = LastSearchPosition;
  811.  
  812.                             do
  813.                             {
  814.                                 PatternIndex = 0;
  815.                                 LineIndex = SearchPosition - 1;
  816.  
  817.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  818.                                 {
  819.                                     LineIndex++;
  820.                                     PatternIndex++;
  821.                                 }
  822.  
  823.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  824.  
  825.                                 if(PatternIndex == PatternWidth)
  826.                                 {
  827.                                     LONG X = LineIndex - PatternWidth;
  828.  
  829.                                     if(X)
  830.                                     {
  831.                                         if(!WordSeparators[Line[X - 1]])
  832.                                             continue;
  833.                                         else
  834.                                         {
  835.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  836.                                                 continue;
  837.                                         }
  838.                                     }
  839.                                     else
  840.                                     {
  841.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  842.                                             continue;
  843.                                     }
  844.  
  845.                                     Info -> FoundX    = LineIndex - PatternWidth;
  846.                                     Info -> FoundY    = i;
  847.                                     Info -> Index    = SearchPosition;
  848.  
  849.                                     return(i);
  850.                                 }
  851.                             }
  852.                             while(SearchPosition > 0);
  853.                         }
  854.  
  855.                         LastSearchPosition = 0;
  856.                     }
  857.                 }
  858.             }
  859.         }
  860.         else
  861.         {
  862.                 /* Which direction are we to search? */
  863.  
  864.             if(Info -> IgnoreCase)
  865.             {
  866.                 if(Info -> Forward)
  867.                 {
  868.                         /* Update the search positions. */
  869.  
  870.                     if(Info -> FoundY == -1)
  871.                     {
  872.                         Info -> FoundX        = 0;
  873.                         Info -> FoundY        = 0;
  874.                         LastSearchPosition    = 0;
  875.                     }
  876.                     else
  877.                     {
  878.                             /* Proceed to the next line. */
  879.  
  880.                         if(!(LastSearchPosition = Info -> Index))
  881.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  882.                     }
  883.  
  884.                         /* Run down the buffer. */
  885.  
  886.                     for(i = Info -> FoundY ; i < Lines ; i++)
  887.                     {
  888.                         Line = BufferLines[i];
  889.  
  890.                             /* Is there anything to search for? */
  891.  
  892.                         if((LineWidth = Line[-1]) >= PatternWidth)
  893.                         {
  894.                                 /* Where are we to start searching? */
  895.  
  896.                             if(LastSearchPosition)
  897.                                 SearchPosition = LastSearchPosition;
  898.                             else
  899.                                 SearchPosition = PatternWidth;
  900.  
  901.                             do
  902.                             {
  903.                                     /* How many line characters
  904.                                      * match the pattern?
  905.                                      */
  906.  
  907.                                 PatternIndex    = PatternWidth - 1;
  908.                                 LineIndex    = SearchPosition - 1;
  909.  
  910.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  911.                                 {
  912.                                     LineIndex--;
  913.                                     PatternIndex--;
  914.                                 }
  915.  
  916.                                     /* Update the line search index
  917.                                      * for subsequent searches.
  918.                                      */
  919.  
  920.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  921.  
  922.                                     /* Found the pattern? */
  923.  
  924.                                 if(PatternIndex < 0)
  925.                                 {
  926.                                         /* Store the position. */
  927.  
  928.                                     Info -> FoundX    = LineIndex + 1;
  929.                                     Info -> FoundY    = i;
  930.  
  931.                                         /* Remember column to start
  932.                                          * next search attempt at.
  933.                                          */
  934.  
  935.                                     if(SearchPosition <= LineWidth)
  936.                                         Info -> Index = SearchPosition;
  937.                                     else
  938.                                         Info -> Index = 0;
  939.  
  940.                                     return(i);
  941.                                 }
  942.                             }
  943.                             while(SearchPosition <= LineWidth);
  944.                         }
  945.  
  946.                             /* Reset search column. */
  947.  
  948.                         LastSearchPosition = 0;
  949.                     }
  950.                 }
  951.                 else
  952.                 {
  953.                         /* Update the search positions. */
  954.  
  955.                     if(Info -> FoundY == -1)
  956.                     {
  957.                         Info -> FoundX        = 0;
  958.                         Info -> FoundY        = Lines - 1;
  959.                         LastSearchPosition    = 0;
  960.                     }
  961.                     else
  962.                     {
  963.                         if((LastSearchPosition = Info -> Index) < 1)
  964.                         {
  965.                             if(Info -> FoundY)
  966.                                 Info -> FoundY--;
  967.                             else
  968.                                 Info -> FoundY = Lines - 1;
  969.                         }
  970.                     }
  971.  
  972.                         /* Run down the buffer. */
  973.  
  974.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  975.                     {
  976.                         Line = BufferLines[i];
  977.  
  978.                             /* Is there anything to search for? */
  979.  
  980.                         if((LineWidth = Line[-1]) >= PatternWidth)
  981.                         {
  982.                                 /* Cast the magic spell of Boyer-Moore... */
  983.  
  984.                             if(LastSearchPosition < 1)
  985.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  986.                             else
  987.                                 SearchPosition = LastSearchPosition;
  988.  
  989.                             do
  990.                             {
  991.                                 PatternIndex = 0;
  992.                                 LineIndex = SearchPosition - 1;
  993.  
  994.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  995.                                 {
  996.                                     LineIndex++;
  997.                                     PatternIndex++;
  998.                                 }
  999.  
  1000.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  1001.  
  1002.                                 if(PatternIndex == PatternWidth)
  1003.                                 {
  1004.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1005.                                     Info -> FoundY    = i;
  1006.                                     Info -> Index    = SearchPosition;
  1007.  
  1008.                                     return(i);
  1009.                                 }
  1010.                             }
  1011.                             while(SearchPosition > 0);
  1012.                         }
  1013.  
  1014.                         LastSearchPosition = 0;
  1015.                     }
  1016.                 }
  1017.             }
  1018.             else
  1019.             {
  1020.                 if(Info -> Forward)
  1021.                 {
  1022.                         /* Update the search positions. */
  1023.  
  1024.                     if(Info -> FoundY == -1)
  1025.                     {
  1026.                         Info -> FoundX        = 0;
  1027.                         Info -> FoundY        = 0;
  1028.                         LastSearchPosition    = 0;
  1029.                     }
  1030.                     else
  1031.                     {
  1032.                             /* Proceed to the next line. */
  1033.  
  1034.                         if(!(LastSearchPosition = Info -> Index))
  1035.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  1036.                     }
  1037.  
  1038.                         /* Run down the buffer. */
  1039.  
  1040.                     for(i = Info -> FoundY ; i < Lines ; i++)
  1041.                     {
  1042.                         Line = BufferLines[i];
  1043.  
  1044.                             /* Is there anything to search for? */
  1045.  
  1046.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1047.                         {
  1048.                                 /* Where are we to start searching? */
  1049.  
  1050.                             if(LastSearchPosition)
  1051.                                 SearchPosition = LastSearchPosition;
  1052.                             else
  1053.                                 SearchPosition = PatternWidth;
  1054.  
  1055.                             do
  1056.                             {
  1057.                                     /* How many line characters
  1058.                                      * match the pattern?
  1059.                                      */
  1060.  
  1061.                                 PatternIndex    = PatternWidth - 1;
  1062.                                 LineIndex    = SearchPosition - 1;
  1063.  
  1064.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  1065.                                 {
  1066.                                     LineIndex--;
  1067.                                     PatternIndex--;
  1068.                                 }
  1069.  
  1070.                                     /* Update the line search index
  1071.                                      * for subsequent searches.
  1072.                                      */
  1073.  
  1074.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  1075.  
  1076.                                     /* Found the pattern? */
  1077.  
  1078.                                 if(PatternIndex < 0)
  1079.                                 {
  1080.                                         /* Store the position. */
  1081.  
  1082.                                     Info -> FoundX    = LineIndex + 1;
  1083.                                     Info -> FoundY    = i;
  1084.  
  1085.                                         /* Remember column to start
  1086.                                          * next search attempt at.
  1087.                                          */
  1088.  
  1089.                                     if(SearchPosition <= LineWidth)
  1090.                                         Info -> Index = SearchPosition;
  1091.                                     else
  1092.                                         Info -> Index = 0;
  1093.  
  1094.                                     return(i);
  1095.                                 }
  1096.                             }
  1097.                             while(SearchPosition <= LineWidth);
  1098.                         }
  1099.  
  1100.                             /* Reset search column. */
  1101.  
  1102.                         LastSearchPosition = 0;
  1103.                     }
  1104.                 }
  1105.                 else
  1106.                 {
  1107.                         /* Update the search positions. */
  1108.  
  1109.                     if(Info -> FoundY == -1)
  1110.                     {
  1111.                         Info -> FoundX        = 0;
  1112.                         Info -> FoundY        = Lines - 1;
  1113.                         LastSearchPosition    = 0;
  1114.                     }
  1115.                     else
  1116.                     {
  1117.                         if((LastSearchPosition = Info -> Index) < 1)
  1118.                         {
  1119.                             if(Info -> FoundY)
  1120.                                 Info -> FoundY--;
  1121.                             else
  1122.                                 Info -> FoundY = Lines - 1;
  1123.                         }
  1124.                     }
  1125.  
  1126.                         /* Run down the buffer. */
  1127.  
  1128.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  1129.                     {
  1130.                         Line = BufferLines[i];
  1131.  
  1132.                             /* Is there anything to search for? */
  1133.  
  1134.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1135.                         {
  1136.                                 /* Cast the magic spell of Boyer-Moore... */
  1137.  
  1138.                             if(LastSearchPosition < 1)
  1139.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1140.                             else
  1141.                                 SearchPosition = LastSearchPosition;
  1142.  
  1143.                             do
  1144.                             {
  1145.                                 PatternIndex = 0;
  1146.                                 LineIndex = SearchPosition - 1;
  1147.  
  1148.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  1149.                                 {
  1150.                                     LineIndex++;
  1151.                                     PatternIndex++;
  1152.                                 }
  1153.  
  1154.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  1155.  
  1156.                                 if(PatternIndex == PatternWidth)
  1157.                                 {
  1158.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1159.                                     Info -> FoundY    = i;
  1160.                                     Info -> Index    = SearchPosition;
  1161.  
  1162.                                     return(i);
  1163.                                 }
  1164.                             }
  1165.                             while(SearchPosition > 0);
  1166.                         }
  1167.  
  1168.                         LastSearchPosition = 0;
  1169.                     }
  1170.                 }
  1171.             }
  1172.         }
  1173.     }
  1174.  
  1175.     return(-1);
  1176. }
  1177.  
  1178. STATIC ULONG __asm __saveds
  1179. HistoryFunc(register __a0 struct Hook *Hook,register __a1 STRPTR NewString)
  1180. {
  1181.     struct List *List = (struct List *)Hook -> h_Data;
  1182.  
  1183.     if(NewString)
  1184.     {
  1185.         struct Node *Node = CreateNode(NewString);
  1186.  
  1187.         if(Node)
  1188.             AddTail(List,Node);
  1189.         else
  1190.             return(FALSE);
  1191.     }
  1192.     else
  1193.     {
  1194.         struct Node *Node = RemHead(List);
  1195.  
  1196.         FreeNode(Node);
  1197.     }
  1198.  
  1199.     return(TRUE);
  1200. }
  1201.  
  1202. BOOLEAN __regargs
  1203. HandleSearchMessage(struct SearchContext *Context,struct IntuiMessage **MessagePtr)
  1204. {
  1205.     struct IntuiMessage    *Message;
  1206.     BOOLEAN             Done = FALSE;
  1207.  
  1208.     if(Message = GT_FilterIMsg(*MessagePtr))
  1209.     {
  1210.         ULONG         MsgClass    = Message -> Class,
  1211.                  MsgQualifier    = Message -> Qualifier;
  1212.         struct Gadget    *MsgGadget    = (struct Gadget *)Message -> IAddress;
  1213.         UWORD         MsgCode    = Message -> Code;
  1214.  
  1215.         LT_HandleInput(Context -> SearchHandle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  1216.  
  1217.         if(MsgClass == IDCMP_CLOSEWINDOW)
  1218.             Done = TRUE;
  1219.  
  1220.         if(MsgClass == IDCMP_GADGETUP)
  1221.         {
  1222.             switch(MsgGadget -> GadgetID)
  1223.             {
  1224.                 case GAD_STRING:
  1225.  
  1226.                     if(MsgCode == '\r')
  1227.                     {
  1228.                         if(Context -> LocalBuffer[0])
  1229.                         {
  1230.                             strcpy(Context -> Buffer,Context -> LocalBuffer);
  1231.  
  1232.                             Context -> Ok = TRUE;
  1233.  
  1234.                             LT_PressButton(Context -> SearchHandle,GAD_OK);
  1235.                         }
  1236.                         else
  1237.                             LT_PressButton(Context -> SearchHandle,GAD_CANCEL);
  1238.  
  1239.                         Done = TRUE;
  1240.                     }
  1241.  
  1242.                     break;
  1243.  
  1244.                 case GAD_OK:
  1245.  
  1246.                     LT_UpdateStrings(Context -> SearchHandle);
  1247.  
  1248.                     if(Context -> LocalBuffer[0])
  1249.                     {
  1250.                         strcpy(Context -> Buffer,Context -> LocalBuffer);
  1251.  
  1252.                         Context -> Ok = TRUE;
  1253.                     }
  1254.  
  1255.                     Done = TRUE;
  1256.  
  1257.                     break;
  1258.  
  1259.                 case GAD_CANCEL:
  1260.  
  1261.                     Done = TRUE;
  1262.  
  1263.                     break;
  1264.             }
  1265.         }
  1266.  
  1267.         GT_PostFilterIMsg(Message);
  1268.     }
  1269.  
  1270.     ReplyMsg(*MessagePtr);
  1271.  
  1272.     *MessagePtr = NULL;
  1273.  
  1274.     return(Done);
  1275. }
  1276.  
  1277. VOID __regargs
  1278. DeleteSearchContext(struct SearchContext *Context)
  1279. {
  1280.     if(Context)
  1281.     {
  1282.         LT_DeleteHandle(Context -> SearchHandle);
  1283.  
  1284.         DISPOSE(Context);
  1285.     }
  1286. }
  1287.  
  1288. struct SearchContext * __regargs
  1289. CreateSearchContext(struct Window *ParentWindow,STRPTR Buffer,struct Hook *HistoryHook,BOOLEAN *Forward,BOOLEAN *IgnoreCase,BOOLEAN *WholeWords)
  1290. {
  1291.     struct SearchContext *Context;
  1292.  
  1293.     if(NEW(Context))
  1294.     {
  1295.         struct LayoutHandle *Handle;
  1296.  
  1297.         Context -> Buffer = Buffer;
  1298.  
  1299.         if(HistoryHook)
  1300.             HistoryHook -> h_Entry = (HOOKFUNC)HistoryFunc;
  1301.  
  1302.         if(Handle = LT_CreateHandleTags(ParentWindow -> WScreen,
  1303.             LH_LocaleHook,    &LocaleHook,
  1304.         TAG_DONE))
  1305.         {
  1306.             struct Window *Window;
  1307.  
  1308.             LT_New(Handle,
  1309.                 LA_Type,    VERTICAL_KIND,
  1310.             TAG_DONE);
  1311.             {
  1312.                 LT_New(Handle,
  1313.                     LA_Type,    HORIZONTAL_KIND,
  1314. //                    LA_LabelText,    LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),
  1315.                 TAG_DONE);
  1316.                 {
  1317.                     LT_New(Handle,
  1318.                         LA_Type,    VERTICAL_KIND,
  1319.                     TAG_DONE);
  1320.                     {
  1321.                         LT_New(Handle,
  1322.                             LA_Type,        STRING_KIND,
  1323.                             LA_LabelID,        MSG_V36_0788,
  1324.                             LA_STRPTR,        Context -> LocalBuffer,
  1325.                             LA_Chars,        30,
  1326.                             LA_ID,            GAD_STRING,
  1327.                             LAST_HistoryLines,    MAX(Config -> CaptureConfig -> SearchHistory,1),
  1328.                             LAST_HistoryHook,    HistoryHook,
  1329.                             GTST_MaxChars,        255,
  1330.                         TAG_DONE);
  1331.  
  1332.                         LT_EndGroup(Handle);
  1333.                     }
  1334.  
  1335.                     LT_New(Handle,
  1336.                         LA_Type,    VERTICAL_KIND,
  1337.                     TAG_DONE);
  1338.                     {
  1339.                         LT_New(Handle,
  1340.                             LA_Type,YBAR_KIND,
  1341.                         TAG_DONE);
  1342.  
  1343.                         LT_EndGroup(Handle);
  1344.                     }
  1345.  
  1346.                     LT_New(Handle,
  1347.                         LA_Type,    VERTICAL_KIND,
  1348.                     TAG_DONE);
  1349.                     {
  1350.                         LT_New(Handle,
  1351.                             LA_Type,    CHECKBOX_KIND,
  1352.                             LA_LabelID,    MSG_TERMBUFFER_SEARCH_FORWARD_TXT,
  1353.                             LA_BYTE,    Forward,
  1354.                         TAG_DONE);
  1355.  
  1356.                         LT_New(Handle,
  1357.                             LA_Type,    CHECKBOX_KIND,
  1358.                             LA_LabelID,    MSG_TEXTBUFFER_IGNORE_CASE_GAD,
  1359.                             LA_BYTE,    IgnoreCase,
  1360.                         TAG_DONE);
  1361.  
  1362.                         LT_New(Handle,
  1363.                             LA_Type,    CHECKBOX_KIND,
  1364.                             LA_LabelID,    MSG_SEARCH_ONLY_WHOLE_WORDS_TXT,
  1365.                             LA_BYTE,    WholeWords,
  1366.                         TAG_DONE);
  1367.  
  1368.                         LT_EndGroup(Handle);
  1369.                     }
  1370.  
  1371.                     LT_EndGroup(Handle);
  1372.                 }
  1373.  
  1374.                 LT_New(Handle,
  1375.                     LA_Type,    VERTICAL_KIND,
  1376.                 TAG_DONE);
  1377.                 {
  1378.                     LT_New(Handle,LA_Type,XBAR_KIND,LAXB_FullSize,TRUE,TAG_DONE);
  1379.  
  1380.                     LT_EndGroup(Handle);
  1381.                 }
  1382.  
  1383.                 LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1384.                     LAGR_SameSize,    TRUE,
  1385.                     LAGR_Spread,    TRUE,
  1386.                 TAG_DONE);
  1387.                 {
  1388.                     LT_New(Handle,
  1389.                         LA_Type,    BUTTON_KIND,
  1390.                         LA_LabelID,    MSG_TERMXPR_OKAY_GAD,
  1391.                         LA_ID,        GAD_OK,
  1392.                         LABT_ReturnKey,    TRUE,
  1393.                         LABT_ExtraFat,    TRUE,
  1394.                     TAG_DONE);
  1395.  
  1396.                     LT_New(Handle,
  1397.                         LA_Type,    BUTTON_KIND,
  1398.                         LA_LabelID,    MSG_GLOBAL_CANCEL_GAD,
  1399.                         LA_ID,        GAD_CANCEL,
  1400.                         LABT_EscKey,    TRUE,
  1401.                         LABT_ExtraFat,    TRUE,
  1402.                     TAG_DONE);
  1403.  
  1404.                     LT_EndGroup(Handle);
  1405.                 }
  1406.  
  1407.                 LT_EndGroup(Handle);
  1408.             }
  1409.  
  1410.             if(Window = LT_Layout(Handle,LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),NULL,0,0,IDCMP_CLOSEWINDOW,0,
  1411.                 LAWN_HelpHook,        &GuideHook,
  1412.                 LAWN_Parent,        ParentWindow,
  1413.                 LAWN_UserPort,        ParentWindow -> UserPort,
  1414.                 WA_DepthGadget,        TRUE,
  1415.                 WA_CloseGadget,        TRUE,
  1416.                 WA_DragBar,        TRUE,
  1417.                 WA_RMBTrap,        TRUE,
  1418.                 WA_Activate,        TRUE,
  1419.             TAG_DONE))
  1420.             {
  1421.                 LT_Activate(Handle,GAD_STRING);
  1422.  
  1423.                 Context -> SearchHandle    = Handle;
  1424.                 Context -> SearchWindow = Window;
  1425.  
  1426.                 return(Context);
  1427.             }
  1428.         }
  1429.  
  1430.         DISPOSE(Context);
  1431.     }
  1432.  
  1433.     return(NULL);
  1434. }
  1435.